/*
 * RentalDAO.java
 *
 * Created on March 25, 2007, 1:35 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package finalintex2web;

//import com.sun.crypto.provider.RSACipher;

import java.sql.*;
import java.util.*;

public class RentalDAO extends RevenueSourceDAO{
    
    ///////////////////////////////////////
    ///   Singleton pattern
    
    private static RentalDAO instance = null;
    
    /** Creates a new instance of RentalDAO */
    private RentalDAO() {
    }
    
    public static synchronized RentalDAO getInstance() {
        if (instance == null) {
            instance = new RentalDAO();
        }
        return instance;
    }
    
    
    /////////////////////////////////
    ///   CREATE
    
    /**
     * This method is used to create the business object. This method first
     * generates GUID to provide unique identifier to the business object
     * and then puts the business object in the cache.
     *
     * @return RentalBO rental;
     */
    public RentalBO create() {
        RentalBO rental = null;
        try {
            //generate GUID
            String id = GUID.generate();
            //create Print Order Line Business Object
            rental = new RentalBO(id);
            //add Print Order Line Business object to cache
            Cache c = Cache.getInstance();
            c.put(rental.getId(), rental);
        } //catch (DataException ex) {
        //  ex.printStackTrace();
        //   }
        catch (Exception ex) {
            ex.printStackTrace();
        }
        return rental;
    }
    
    
    /////////////////////////////////////
    ///   READ
    
    /**
     * This is the public read statement. This method loads an existing
     * record from the database in the form of an object
     *
     * @param String id
     * @return RentalBO rental
     */
    public synchronized RevenueSourceBO read(String id) throws DataException {
//        System.out.println(id);
        /*initialize RentalBO and Connection variables*/
        RentalBO rental = null;
        Connection conn = null;
        // check to see if id in the cache
        Cache c = Cache.getInstance();
        if(c.get(id)!=null){
            rental = (RentalBO)(c.get(id));
        } else{
            try {
                //call the other read method
                conn = ConnectionPool.getInstance().get();
                rental = (RentalBO) read(id, conn);
                ConnectionPool.getInstance().release(conn);
            }catch (Exception e) {
                throw new DataException("Could not retrieve record for id=" + id, e);
            }
        }
        
        return rental;
    }
    
    /**
     *  This is a package method that is called by the public read (above) or
     *  by another DAO.  Either way we already have a connection to the database
     *  to use.  The user (controller) code never calls this one directly, since
     *  it can't know about Connection objects or SQLExceptions.
     *
     *  @param String id
     *         Connection conn
     * @return RentalBO rental
     */
    public synchronized RevenueSourceBO read(String id, Connection conn) throws SQLException, DataException {
        RentalBO rental = null;
        // check cache and return if found
        Cache c = Cache.getInstance();
        if(c.get(id)!=null){
            return (RentalBO)(c.get(id));
        } else{
            // if not in the cache, get a result set from database
            PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM Rental WHERE rsid=?");
            //give the value of id
            pstmt.setString(1,id);
            ResultSet rs = pstmt.executeQuery();
            
            if(rs.next()){
                //create and set variables for RentalBO
                rental = new RentalBO(id);
                rental.setDateOut(rs.getString("dateout"));
                rental.setDateDue(rs.getString("datedue"));
                rental.setForRentID(rs.getString("forrentid"));
                rental.setAlreadyInDB(true);
                
                //RevenueSourceBO in cache
                c.put(id,rental);
                //super.read(id,conn);
            } else{
                throw new DataException("Object was not found in the database.");
            }
        }
        return rental;
    }
    
    
    //////////////////////////////////
    ///   UPDATE
    
    /**
     * This is the public save method.  It is what is called when
     * the user (controller) code wants to save or update an object
     * into the database.
     *
     * @param RentalBO rental
     *
     */
    public synchronized void save(RevenueSourceBO rental) throws DataException {
        //initialize connection variable
        Connection conn = null;
        try {
            conn = ConnectionPool.getInstance().get();
            //call the other save method
            save(rental, conn);
            ConnectionPool.getInstance().release(conn);
        }catch (Exception ex) {
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throw new DataException("Could not save the record");
        }
    }
    
    /**
     * This is a package method that is called by the public save (above) or
     * by another DAO.  Either way we already have a connection to the database
     * to use.  The user (controller) code never calls this one directly, since
     * it can't know about Connection objects or SQLExceptions.
     *
     * This method will decide wether to update or insert the record in the database
     * depending on the isAlreadyInDB method
     *
     * @param RentalBO rental
     *        Connection conn
     *
     */
    public synchronized void save(RevenueSourceBO rental, Connection conn) throws SQLException, DataException, ConnectionPoolException {
        try {
            // check the dirty flag in the object.  if it is dirty,
            // run update or insert
            if (rental.isDirty()) {
                //update record if already in database
                if (rental.isIndb()) {
                    update((RentalBO) rental, conn);
                }
                //insert record if not in database
                else{
                    insert((RentalBO) rental, conn);
                }
                // set the dirty flag to false now that we've saved it
                rental.setDirty(false);
                //renew object in cache
                Cache c = Cache.getInstance();
                c.touch(rental.getId());
            }
        } catch (DataException ex) {
            throw ex;
        } catch (SQLException ex) {
            throw ex;
        }
        
    }
    
    /**
     * This method is really a part of save(bo, conn) above.  It could be
     * embedded directly in it, but I've separated it into it's own method
     * to isolate the SQL udpate statement and make it more readable.  But
     * logically, it's really just a part of save.
     *
     * @param RentalBO rental
     *        Connection conn
     *
     */
    private synchronized void update(RentalBO rental, Connection conn) throws SQLException, DataException, ConnectionPoolException {
        
        // do the update statement
        PreparedStatement pstmt = conn.prepareStatement("UPDATE Rental SET dateout=?,datedue=?,forrentid=? WHERE rsid=?");
        try {
            pstmt.setString(1,rental.getDateOut());
            pstmt.setString(2,rental.getDateDue());
            pstmt.setString(3,rental.getForRentID());
            pstmt.setString(4,rental.getId());
            
            
            //execute and commit the statement
            pstmt.executeUpdate();
            pstmt.close();
            conn.commit();
            
            super.save(rental,conn);
        } catch (SQLException ex) {
            throw ex;
        }
    }
    
    /**
     * This method is really a part of save(bo, conn) above.  It could be
     * embedded directly in it, but I've separated it into it's own method
     * to isolate the SQL insert statement and make it more readable.  But
     * logically, it's really just a part of save.
     *
     * @param RentalBO rental
     *        Connection conn
     */
    private synchronized void insert(RentalBO rental, Connection conn) throws SQLException, DataException, ConnectionPoolException {
        
        // do the insert SQL statement
        PreparedStatement pstmt = conn.prepareStatement("INSERT INTO Rental (dateout,datedue,forrentid,rsid) VALUES (?,?,?,?)");
        try {
            pstmt.setString(1,rental.getDateOut());
            pstmt.setString(2,rental.getDateDue());
            pstmt.setString(3,rental.getForRentID());
            pstmt.setString(4,rental.getId());
            
            //execute and commit the statement
            pstmt.executeUpdate();
            pstmt.close();
            conn.commit();
            
            super.save(rental,conn);
        } catch (SQLException ex) {
            throw ex;
        }
        // tell the object that it's now in the db (so we call update next time not insert)
        rental.setAlreadyInDB(true);
    }
    
    
    ////////////////////////////////////
    ///   DELETE
    
    // we are not supporting because deleting customer will
    //create referential error
    
    
    /**
     *  This is a package method that is called by the public read (above) or
     *  by another DAO.  Either way we already have a connection to the database
     *  to use.  The user (controller) code never calls this one directly, since
     *  it can't know about Connection objects or SQLExceptions.
     *
     *  @param Connection conn
     *  @return List<RevenueSourceBO> list
     */
    public synchronized List<RevenueSourceBO> readAll(Connection conn) throws SQLException, DataException {
        List<RevenueSourceBO> list = new ArrayList<RevenueSourceBO>();
        RentalBO rental = null;
        Cache c = Cache.getInstance();
        // if not in the cache, get a result set from database
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT * FROM rental");
        
        if(rs.next()){
            //create and set variables for RentalBO
            rental = new RentalBO(rs.getString("rsid"));
            rental.setDateOut(rs.getString("dateout"));
            rental.setDateDue(rs.getString("datedue"));
            rental.setForRentID(rs.getString("forrentid"));
            rental.setAlreadyInDB(true);
            
            //RevenueSourceBO in cache
            c.put(rental.getId(),rental);
            //super.
            read(rental.getId(),conn);
            
            list.add(rental);
        } else{
            throw new DataException("Object was not found in the database.");
        }
        
        return list;
    }
}